package com.juanLL.CMC.models;

import java.util.Random;

import android.graphics.Bitmap;

import com.juanLL.CMC.AssetLoader;

public class Trash extends Model {

	// tag constant id for debugging
	public static final String TAG = "Trash";
	// launch calculation variables
	private float launchAngle;
	private int launchDir;
	private float launchSpeed;
	// position at which the object was first touched, x and y
	public float xTouchPos;
	public float yTouchPos;
	// variables to aid in difference of position calculation
	private float dX;
	private float dY;
	// speed damper factor for collisions
	public float speedDamper = 0.2f;
	// floor friction factor
	public float floorFriction = 0.1f;
	// factor that scales the power of the launch
	public float launchScalingFactor = 0.1f;
	// Random object to randomize the launch calculation
	Random rand = new Random();
	// boolean state variables
	public boolean isFalling = false;
	public boolean isInitial = false;
	public boolean isTouched = false;
	public boolean isLaunched = false;
	public boolean isStolen = false;
	// Constants that control Angle and Speed launch parameters
	public static final int MAX_LAUNCH_ANGLE = 90;
	public static final int MIN_LAUNCH_ANGLE = 45;
	public static final int MAX_LAUNCH_SPEED = 20;
	public static final int MIN_LAUNCH_SPEED = 15;
	// State id constants
	public static final int STATE_INITIAL = 0;
	public static final int STATE_FALLING = 1;
	public static final int STATE_TOUCHED = 2;
	public static final int STATE_LAUNCHING = 3;
	public static final int STATE_LAUNCHED = 4;
	public static final int STATE_STOLEN = 5;

	// Gravity constant from GameWorld
	public static final Float GRAVITY = GameWorld.GRAVITY;

	// enum that contains the type and path to bitmap of all trash objects
	public static enum trashEnum {
		GBOTTLE(Model.TYPE_GLASS, AssetLoader.PATH_TRASH_GBOTTLE), GJAR(
				Model.TYPE_GLASS, AssetLoader.PATH_TRASH_GJAR), PBOTTLE(
				Model.TYPE_PLASTIC, AssetLoader.PATH_TRASH_PBOTTLE), PBAG(
				Model.TYPE_PLASTIC, AssetLoader.PATH_TRASH_PBAG), OAPPLE(
				Model.TYPE_ORGANIC, AssetLoader.PATH_TRASH_OAPPLE), OBANANA(
				Model.TYPE_ORGANIC, AssetLoader.PATH_TRASH_OBANANA);

		// type id constant from Model class
		public int type;
		// the full path to the bitmap file
		public String path;

		/**
		 * trashEnum constructor
		 * 
		 * @param type
		 *            the type id constant
		 * @param path
		 *            the full path to the bitmap file
		 */
		trashEnum(int type, String path) {
			this.type = type;
			this.path = path;
		}

	}

	/**
	 * Trash constructor
	 * 
	 * @param type
	 *            the type id constant from the Model class
	 * @param bitmap
	 *            the bitmap that represents the object graphically
	 */
	public Trash(int type, Bitmap bitmap) {
		this.type = type;
		this.bitmap = bitmap;
		// set the default initial state at construction
		this.setState(STATE_INITIAL);
	}

	/**
	 * Override of the update() method of the model class to decrease ySpeed
	 * according to gravity
	 */
	@Override
	public void update() {
		super.update();
		if (!isTouched && !isStolen)
			// change ySpeed according to gravity
			ySpeed += GRAVITY;
	}

	/**
	 * launch method, sets a random angle, speed and direction and applies them
	 * to the Trash Object
	 * 
	 * @param x
	 *            the x coordinate position of the citizen
	 * @param y
	 *            the y coordinate position of the citizen
	 */
	public void launch(float x, float y) {
		// generate a random angle within the limits
		launchAngle = rand.nextFloat()
				* (Trash.MAX_LAUNCH_ANGLE - Trash.MIN_LAUNCH_ANGLE)
				+ Trash.MIN_LAUNCH_ANGLE;
		// generate a random direction
		launchDir = (int) Math.pow(-1, rand.nextInt(1 + 1));
		// generate a random launch speed within the limits
		launchSpeed = rand.nextFloat()
				* (Trash.MAX_LAUNCH_SPEED - Trash.MIN_LAUNCH_SPEED)
				+ Trash.MIN_LAUNCH_SPEED;
		// calculate the xSpeed vector from the launch speed and angle values
		// and set the direction
		xSpeed = (float) ((launchSpeed * Math.cos(launchAngle)) * launchDir);
		// calculate the xSpeed vector from the launch speed and angle values
		// and set the direction upwards
		ySpeed = (float) ((launchSpeed * Math.sin(Math.toRadians(launchAngle))) * -1);
		// set the new state
		setState(STATE_FALLING);
		// set the draw boolean value according to the state
		draw = true;
		this.x = x;
		this.y = y - 5;
	}

	/**
	 * touched method, called when a user touches this specific trash object
	 * 
	 * @param x
	 *            the x coordinate where the user touched the trash object
	 * @param y
	 *            the y coordinate where the user touched the trash object
	 */
	public void touched(Float x, Float y) {
		this.x = xTouchPos = x;
		this.y = yTouchPos = y;
		ySpeed = xSpeed = 0;
		this.setState(STATE_TOUCHED);
	}

	/**
	 * touchedAndMove method, called when the user slides the finger away from
	 * the trash object to prepare a launch
	 * 
	 * @param x
	 *            the x coordinate to where the user slid his finger
	 * @param y
	 *            the y coordinate to where the user slid his finger
	 */
	public void touchedAndMove(float x, float y) {
		this.x = xTouchPos = x;
		this.y = yTouchPos = y;

	}

	/**
	 * launched method, called after the user releases the trash object(lifts
	 * his finger up after touching the object), launches the trash
	 * 
	 * @param x
	 * @param y
	 */
	public void launched(float x, float y) {
		dX = x - xTouchPos;
		dY = y - yTouchPos;
		xSpeed = dX;
		ySpeed = dY;
		this.setState(STATE_LAUNCHED);
	}

	/**
	 * borderCollisionX method, inverts xSpeed, to be used after collision
	 * detection
	 */
	public void borderCollisionX() {
		xSpeed *= speedDamper * -1;
	}

	/**
	 * borderCollisionY method, inverts ySpeed, to be used after collision
	 * detection
	 */
	public void borderCollisionY() {
		ySpeed *= speedDamper * -1;
	}

	/**
	 * floorFriction method, applies a damper to xSpeed.
	 */
	public void floorFriction() {
		xSpeed *= floorFriction;
	}

	/**
	 * catched method, resets a Trash object to be recycled after being catched
	 * by a recycle bin
	 */
	public void catched() {
		draw = false;
		x = -100;
		xSpeed = ySpeed = 0;
		this.setState(STATE_INITIAL);
	}

	/**
	 * setState method, changes the state of the object and updates boolean
	 * variables to reflect it
	 * 
	 * @param state
	 *            the new state to be set
	 */
	public void setState(int state) {
		switch (state) {
		case STATE_INITIAL:
			this.state = STATE_INITIAL;
			isInitial = true;
			isFalling = false;
			isTouched = false;
			isStolen = false;
			break;
		case STATE_FALLING:
			isFalling = true;
			isInitial = false;
			isTouched = false;
			isStolen = false;
			break;
		case STATE_TOUCHED:
			isTouched = true;
			isInitial = false;
			isFalling = false;
			isStolen = false;
			break;
		case STATE_LAUNCHING:
			isInitial = false;
			isFalling = false;
			isTouched = false;
			isStolen = false;
			break;
		case STATE_LAUNCHED:
			isLaunched = true;
			isInitial = false;
			isFalling = false;
			isTouched = false;
			isStolen = false;
			break;
		case STATE_STOLEN:
			isStolen = true;
			isLaunched = false;
			isInitial = false;
			isFalling = false;
			isTouched = false;
			break;
		}
	}
}
